package com.ludomancy.starwave;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.util.Hashtable;
import java.util.Vector;

import com.ludomancy.gamelib.ResourceManager;
import com.ludomancy.gamelib.Utils;

public abstract class Ship implements ShipTypes
{
	public Player owner;
	public int px = 0;
	public int py = 0;
	public double hull = 1.0;
	public int type = -1;
	private int initialPx;
	private int initialPy;
	
	public Ship(Player owner, int px, int py)
	{
		this.px = px;
		this.py = py;
		this.initialPx = px;
		this.initialPy = py;
		this.owner = owner;
	}
	
	public void restoreInitialPosition()
	{
		px = initialPx;
		py = initialPy;
	}
	
	public boolean canFire(int tilex, int tiley)
	{
		Point[] arc = getFiringArc();
		for (int k = 0; k < arc.length; k++)
		{
			int tx = arc[k].x + px;
			int ty = arc[k].y + py;
			if(tx == tilex && ty == tiley)
			{
				return true;
			}
		}
		return false;
	}
	
	public Image getIcon()
	{
		boolean right = owner.direction > 0;
		String iconName = null;
		switch(type)
		{
			case FIG:
				iconName = right ? "fighter.png" : "fighter.png";
				break;
			case DEF:
				iconName = right ? "defender.png" : "defender.png";
				break;
			case MIN:
				iconName = right ? "mine.png" : "mine.png";
				break;
			case SLI:
				iconName = right ? "slider.png" : "slider.png";
				break;
			case POR:
				iconName = "portal.png";
				break;
			case WMD:
				iconName = "wmd.png";
				break;
			case SLU:
				iconName = "slider-up.png";
				break;
			case FIA:
				iconName = "armored.png";
				break;			
		}
		return ResourceManager.getImage(iconName);
	}
	
	public void paint(Graphics g, int x, int y)
	{
		paintInYard(g, x, y);
	}
	
	public void paintInYard(Graphics g, int x, int y)
	{
		g.drawImage(getIcon(), x, y, null);
	}
	
	protected void receiveAttack(double damage)
	{
		hull = Math.max(0, hull - damage);
	}
	
	public boolean isDead()
	{
		return hull == 0;
	}
	
	public boolean isSolid()
	{
		return true;
	}
	
	public boolean isMover()
	{
		return false;
	}

	public abstract String getDescription();
	
	protected boolean canMove()
	{
		return isMover();
	}
	
	protected boolean canMoveHere(int tx, int ty)
	{
		if(Game.game.isWithinPlayfield(tx, ty))
		{
			if(!Game.game.isTileSolid(tx, ty, this))
			{
				return true;
			}
		}
		return false;
	}

	protected void shoot(Ship enemy)
	{
		enemy.receiveAttack(1.0);
	}
	
	protected Point[] getFiringArc()
	{
		return new Point[] {new Point(owner.direction,0)};
	}
	
	public Vector scanEnemies(int tx, int ty)
	{
		Vector enemies = new Vector();
		Point[] arc = getFiringArc();
		for( int i = 0 ; i != arc.length ; i++)
		{
			Ship[] enemy = Game.game.getShips(tx + arc[i].x, ty + arc[i].y);
			for (int j = 0; j < enemy.length; j++)
			{
				if(enemy[j].owner != owner && enemy[j].isSolid() && enemy[j] != this && !enemy[j].isDead())
				{
					enemies.add(enemy[j]);
				}
			}
		}
		return enemies;		
	}

	protected Vector scanEnemies()
	{
		return scanEnemies(px, py);
	}
	
	public Vector attack()
	{
		// scan for reachable enemies
		Vector enemies = scanEnemies();
		Game.game.addAnimation(new AttackAnimation(this, enemies));
		return enemies;
	}
	
	public boolean isShooter()
	{
		return true;
	}
	
	public Point[] getPath(int startx, int starty)
	{
		Vector path = new Vector();
		// compute default full path
		Point next = new Point(startx+owner.direction, starty);
		while(canMoveHere(next.x, next.y))
		{
			path.insertElementAt(next, path.size());
			next = new Point(next.x + owner.direction, next.y);
		}
		Point[] ret = new Point[path.size()];
		path.copyInto(ret);
		return ret;
	}
	
	protected Point nextPosition()
	{
		return getPath(px, py)[0];
	}

	public void move()
	{
		// move towards enemy
		if(canMove())
		{
			Point next = nextPosition();
			Game.game.addAnimation(new MoveAnimation(this, next.x, next.y));
			px = next.x;
			py = next.y;
		}
		else
		{
			Game.game.addAnimation(new MoveAnimation(this, px, py));
		}
	}

	public boolean collide(Ship ship, Vector animations)
	{
		return false;
	}

	public void paintDead(Graphics g, int x, int y)
	{
		Utils.pushAlpha(g, 0.45f);
		paint(g, x, y);
		Utils.popAlpha(g);
	}
	
	private static Hashtable typeMap;
	
	public static int stringToType(String type)
	{
		if(typeMap == null)
		{
			typeMap = new Hashtable();
			typeMap.put("NON", new Integer(NON));
			typeMap.put("", new Integer(NON));
			typeMap.put("FIG", new Integer(FIG));
			typeMap.put("MIN", new Integer(MIN));
			typeMap.put("SLI", new Integer(SLI));
			typeMap.put("DEF", new Integer(DEF));
			typeMap.put("POR", new Integer(POR));
			typeMap.put("PLA", new Integer(PLA));
			typeMap.put("WMD", new Integer(WMD));
			typeMap.put("SLU", new Integer(SLU));
			typeMap.put("FIA", new Integer(FIA));
		}
		Integer newType = (Integer) typeMap.get(type);
		return newType.intValue();
	}

	public static Ship createPrototype(int type, Player player, int initialPx, int initialPy)
	{
		Ship s = null;
		switch(type)
		{
			case FIG:
				s = new FighterShip(player, initialPx, initialPy); 
				break;
			case DEF:
				s = new DefenderShip(player, initialPx, initialPy);
				break;
			case MIN:
				s = new MineShip(player, initialPx, initialPy);
				break;
			case SLI:
				s = new SliderShip(player, initialPx, initialPy);
				break;
			case POR:
				s = new PortalShip(player, initialPx, initialPy);
				break;
			case WMD:
				s = new WMDShip(player, initialPx, initialPy);
				break;
			case SLU:
				s = new SliderUpShip(player, initialPx, initialPy);
				break;
			case FIA:
				s = new ArmoredFighterShip(player, initialPx, initialPy);
				break;
			default:
				break;
		}
		return s;
	}
}
